﻿#region License
// MIT License
//
// Copyright(c) 2019-2025 ZhangYu
// https://gitee.com/zhangyu800/litebyte
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#endregion
#region Intro
// Purpose: Convert base type to bytes
// Author: ZhangYu
// CreateDate: 2019-08-13
// LastModifiedDate: 2025-08-30
#endregion
namespace LiteByte.Converters {

    using System;
    using System.Runtime.CompilerServices;

    /// <summary> 数字类型写入器(bool、int、float、vint) | Number type writer </summary>
    public class NumberWriter : IDisposable {

        #region 字段 | Fields
        /// <summary> 最大容量(缓冲区最大字节数 默认10M) </summary>
        public static int MaxCapacity { get; set; } = 1024 * 1024 * 10;
        private static readonly int[] BitMask = [0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF];
        private static readonly byte[] BitMaxValues = [0, 1, 3, 7, 15, 31, 63, 127, 255];
        protected byte[] buffer;               // 字节数组缓冲区 | Byte[]
        protected int byteIndex;               // 当前的字节序号(指向字节数组中的哪一个字节) | Current byte index at byte[] buffer
        protected int bitByteIndex = -1;       // 当前的位序号(指向字节数组中的哪一个字节)   | Current bit index at byte[] buffer
        protected int bitIndex = 8;            // 当前的位的位置(指向一个字节中的哪一位)     | Current bit location at one byte
        protected const int DefaultCapacity = 8; // 默认容量 | Default capacity
        #endregion

        #region 构造方法 | Constructors
        public NumberWriter() {
            buffer = new byte[DefaultCapacity];
        }

        public NumberWriter(int capacity) {
            buffer = new byte[capacity <= 0 ? DefaultCapacity : capacity];
        }
        #endregion

        #region 比特 | Bits
        /// <summary> 写入1位整数(true=1、false=0) | Write 1bit integer(true=1、false=0) </summary>
        public void WriteBit1(bool value) {
            WriteBits(1, value ? (byte)1 : (byte)0);
        }

        /// <summary> 写入2位整数(0~3) | Write 2bits integer(0~3) </summary>
        public void WriteBit2(byte value) {
            WriteBits(2, value);
        }

        /// <summary> 写入3位整数(0~7) | Write 3bits integer(0~7) </summary>
        public void WriteBit3(byte value) {
            WriteBits(3, value);
        }

        /// <summary> 写入4位整数(0~15) | Write 4bits integer(0~15) </summary>
        public void WriteBit4(byte value) {
            WriteBits(4, value);
        }

        /// <summary> 写入5位整数(0~31) | Write 5bits integer(0~31) </summary>
        public void WriteBit5(byte value) {
            WriteBits(5, value);
        }

        /// <summary> 写入6位整数(0~63) | Write 6bits integer(0~63) </summary>
        public void WriteBit6(byte value) {
            WriteBits(6, value);
        }

        /// <summary> 写入7位整数(0~127) | Write 7bits integer(0~127) </summary>
        public void WriteBit7(byte value) {
            WriteBits(7, value);
        }

        /// <summary> 写入8位整数(0~255) | Write 8bits integer(0~255) </summary>
        public void WriteBit8(byte value) {
            WriteBits(8, value);
        }

        /// <summary> 写入1~8位整数 | Write 1~8 bit integer </summary>
        /// <param name="bitCount">位数(1~8)</param>
        /// <param name="value">值</param>
        public void WriteBits(int bitCount, byte value) {
            if (bitCount < 1 || bitCount > 8) throw new ArgumentOutOfRangeException("bitCount", $"WriteBits() bitCount: {bitCount} out of range! bitCount valid range:1 - 8");
            if (value > BitMaxValues[bitCount]) throw new ArgumentOutOfRangeException("value", $"WriteBits() value: {value} out of range! Bit{bitCount} valid range:[0 - {BitMaxValues[bitCount]}]");
            value = (byte)(value & BitMask[bitCount]);
            int freeBitCount = 8 - bitIndex;
            if (freeBitCount >= bitCount) {
                // 写入当前字节
                buffer[bitByteIndex] = (byte)(buffer[bitByteIndex] | value << bitIndex);
                bitIndex += bitCount;
            } else if (freeBitCount > 0) {
                // 跨字节写入
                EnsureCapacity(1);
                int lowBits = value & BitMask[freeBitCount];
                buffer[bitByteIndex] = (byte)(buffer[bitByteIndex] | lowBits << bitIndex);
                int highBits = value >> freeBitCount;
                bitByteIndex = byteIndex++;
                buffer[bitByteIndex] = (byte)highBits;
                bitIndex = bitCount - freeBitCount;
            } else {
                // 写入下一个字节
                EnsureCapacity(1);
                bitByteIndex = byteIndex++;
                buffer[bitByteIndex] = value;
                bitIndex = bitCount;
            }
        }
        #endregion

        #region 整数 | Integer
        /// <summary> 写入布尔型(1字节 true:1 false:0) | Write Boolean(1 byte true:1 false:0) </summary>
        public void WriteBool(bool value) {
            WriteUInt8(value ? (byte)1 : (byte)0);
        }

        /// <summary> 写入字符型(2字节 无符号整数) | Write Char(2 byte unsigned integer) </summary>
        public void WriteChar(char value) {
            WriteUInt16(value);
        }

        /// <summary> 写入UInt8(1字节 无符号整数) | Write UInt8(1 byte unsigned integer) </summary>
        public void WriteUInt8(byte value) {
            EnsureCapacity(1);
            buffer[byteIndex++] = value;
        }

        /// <summary> 写入Int8(1字节 有符号整数) | Write Int8(1 byte signed integer) </summary>
        public void WriteInt8(sbyte value) {
            WriteUInt8((byte)value);
        }

        /// <summary> 写入UInt16(2字节 无符号整数 小端序) | Write UInt16(2 bytes unsigned integer little endian) </summary>
        public void WriteUInt16(ushort value) {
            EnsureCapacity(2);
            Unsafe.As<byte, ushort>(ref buffer[byteIndex]) = value; // buffer[byteIndex++] = (byte)value; buffer[byteIndex++] = (byte)(value >> 8);
            byteIndex += 2;
        }

        /// <summary> 写入Int16(2字节 有符号整数 小端序) | Write Int16(2 bytes signed integer little endian) </summary>
        public void WriteInt16(short value) {
            WriteUInt16((ushort)value);
        }

        /// <summary> 写入UInt32(4字节 无符号整数 小端序) | Write UInt32(4 byte unsigned integer little endian) </summary>
        public void WriteUInt32(uint value) {
            EnsureCapacity(4);
            Unsafe.As<byte, uint>(ref buffer[byteIndex]) = value; // buffer[byteIndex++] = (byte)value; buffer[byteIndex++] = (byte)(value >> 8); buffer[byteIndex++] = (byte)(value >> 16); buffer[byteIndex++] = (byte)(value >> 24);
            byteIndex += 4;
        }

        /// <summary> 写入Int32(4字节 有符号整数 小端序) | Write Int32(4 bytes signed integer little endian) </summary>
        public void WriteInt32(int value) {
            WriteUInt32((uint)value);
        }

        /// <summary> 写入UInt64(8字节 无符号整数 小端序) | Write UInt64(8 byte unsigned integer little endian) </summary>
        public void WriteUInt64(ulong value) {
            EnsureCapacity(8);
            Unsafe.As<byte, ulong>(ref buffer[byteIndex]) = value; // buffer[byteIndex++] = (byte)value; buffer[byteIndex++] = (byte)(value >> 8); buffer[byteIndex++] = (byte)(value >> 16); buffer[byteIndex++] = (byte)(value >> 24); buffer[byteIndex++] = (byte)(value >> 32); buffer[byteIndex++] = (byte)(value >> 40); buffer[byteIndex++] = (byte)(value >> 48); buffer[byteIndex++] = (byte)(value >> 56);
            byteIndex += 8;
        }

        /// <summary> 写入Int64(8字节 有符号整数 小端序) | Write Int64(8 bytes signed integer little endian) </summary>
        public void WriteInt64(long value) {
            WriteUInt64((ulong)value);
        }
        #endregion

        #region 浮点数 | Float
        /// <summary> 写入半精度浮点数(2字节 IEEE754 float16) | Write Half(2 bytes IEEE754 float16) </summary>
        public void WriteFloat16(Half value) {
            ushort bits = Unsafe.As<Half, ushort>(ref value);
            WriteUInt16(bits);
        }

        /*
        /// <summary> 写入Float16(1字节 浮点数 取值范围:[0/255] ~ [255/255] color.r、g、b使用) | Write Float8 </summary>
        public void WriteFloat16(float value) {
            EnsureCapacity(2);
            uint bits = 0;
            unsafe { bits = *(uint*)&value; }
            uint sign = bits >> 31;
            int exponent = (int)((bits >> 23) & 0xFF);
            uint mantissa = bits & 0x7FFFFF;
            // 判断是否为特殊值
            if (exponent == 0xFF) {
                if (mantissa == 0) {
                    // +Infinity(01111100 00000000) 或 -Infinity (11111100 00000000)
                    buffer[byteIndex++] = 0;
                    buffer[byteIndex++] = (byte)(sign == 0 ? 0x7C : 0xFC);
                } else {
                    // NaN(01111100 00000001)
                    buffer[byteIndex++] = 1;
                    buffer[byteIndex++] = 0x7C;
                }
            } else if (exponent == 0 && mantissa == 0) {
                // +0(00000000 00000000) 或 -0(10000000 00000000)
                buffer[byteIndex++] = 0;
                buffer[byteIndex++] = (byte)(sign == 0 ? 0 : 0x80);
            } else {
                // 正常数值 Float -> Half
                // Float to Half 
                // [Sign(1bit) Exponent(8bits) Mantissa(23bits) Bias(127)] -> [Sign(1bit) Exponent(5bits) Mantissa(10bits) Bias(15)]
                // [S EEEEEEEE MMMMMMMM MMMMMMMM MMMMMMM] -> [S EEEEE MM MMMMMMMM]
                exponent = exponent - 127;
                if (exponent >= 15) {
                    // 指数上溢 无穷(+Infinity或-Infinity)
                    buffer[byteIndex++] = 0;
                    buffer[byteIndex++] = (byte)(sign == 0 ? 0x7C : 0xFC);
                } else if (exponent <= -15) {
                    // 指数下溢 +0或-0
                    buffer[byteIndex++] = 1;
                    buffer[byteIndex++] = (byte)(sign == 0 ? 0 : 0x80);
                } else {
                    // Half指数偏移值15
                    exponent += 15;
                    // Half尾数截取10位  0x3FF = 11 11111111
                    mantissa = (mantissa >> 13) & 0x3FF;
                    // 最后一位 四舍五入
                    if ((bits & 0x1000) == 1) mantissa = mantissa | 1;
                    bits = sign << 15 | (uint)exponent << 10 | mantissa;
                    // 写入数值
                    buffer[byteIndex++] = (byte)bits;
                    buffer[byteIndex++] = (byte)(bits >> 8);
                }
            }
        }
        */

        /*
        public void WriteFloat24(float value) {
            EnsureBytes(3);
            // Float32(IEEE 754 32-bit) to Float24
            // [Sign(1bit) Exponent(8bits) Mantissa(23bits) Bias(127)] -> [Sign(1bit) Exponent(7bits) Mantissa(16bits) Bias(63)]
            // [S EEEEEEEE MMMMMMMM MMMMMMMM MMMMMMM] -> [S EEEEEEE MMMMMMMM MMMMMMMM]
        }
        */

        /// <summary> 写入单精度浮点数(4字节 IEEE754 float32) | Write Single(4 bytes IEEE754 float32) </summary>
        public void WriteFloat32(float value) {
            uint bits = Unsafe.As<float, uint>(ref value); // uint bits = 0; unsafe { bits = *(uint*)&value; }
            WriteUInt32(bits);
        }

        /// <summary> 写入双精度浮点数(8字节 IEEE754 float64) | Write Double(8 bytes IEEE754 float64) </summary>
        public void WriteFloat64(double value) {
            ulong bits = Unsafe.As<double, ulong>(ref value); // ulong bits = 0; unsafe { bits = *(ulong*)&value; }
            WriteUInt64(bits);
        }
        #endregion

        #region 变长整数 | Variable-length Integer
        protected void WriteVUInt32(int byteCount, uint value) {
            WriteBits(2, (byte)(byteCount - 1));
            EnsureCapacity(byteCount);
            for (int i = 0; i < byteCount; i++) {
                buffer[byteIndex++] = (byte)(value >> (i * 8));
            }
        }

        protected void WriteVUInt64(int byteCount, ulong value) {
            WriteBits(3, (byte)(byteCount - 1));
            EnsureCapacity(byteCount);
            for (int i = 0; i < byteCount; i++) {
                buffer[byteIndex++] = (byte)(value >> (i * 8));
            }
        }

        public void WriteVUInt16(ushort value) {
            if (value <= 0xFF) {
                WriteBits(1, 0);
                WriteUInt8((byte)value);
            } else {
                WriteBits(1, 1);
                WriteUInt16(value);
            }
        }

        public void WriteVInt16(short value) {
            // 获取符号
            bool isNegative = value < 0 ? true : false;
            // 负数转为正数
            ushort bits = (ushort)(isNegative ? ~value : value);
            if (bits <= 0x7F) {
                WriteBits(1, 0);
                WriteUInt8((byte)(isNegative ? bits | 0x80 : bits));
            } else {
                WriteBits(1, 1);
                WriteUInt16((ushort)(isNegative ? bits | 0x8000 : bits));
            }
        }

        public void WriteVUInt32(uint value) {
            if (value <= 0xFF) {
                WriteVUInt32(1, value);
            } else if (value <= 0xFFFF) {
                WriteVUInt32(2, value);
            } else if (value <= 0xFFFFFF) {
                WriteVUInt32(3, value);
            } else {
                WriteVUInt32(4, value);
            }
        }

        public void WriteVInt32(int value) {
            // 获取符号
            bool isNegative = value < 0 ? true : false;
            // 负数转为正数
            uint bits = (uint)(isNegative ? ~value : value);
            if (bits <= 0x7F) {
                WriteVUInt32(1, isNegative ? bits | 0x80 : bits);
            } else if (bits <= 0x7FFF) {
                WriteVUInt32(2, isNegative ? bits | 0x8000 : bits);
            } else if (bits <= 0x7FFFFF) {
                WriteVUInt32(3, isNegative ? bits | 0x800000 : bits);
            } else {
                WriteVUInt32(4, isNegative ? bits | 0x80000000 : bits);
            }
        }

        public void WriteVUInt64(ulong value) {
            if (value <= 0xFF) {
                WriteVUInt64(1, value);
            } else if (value <= 0xFFFF) {
                WriteVUInt64(2, value);
            } else if (value <= 0xFFFFFF) {
                WriteVUInt64(3, value);
            } else if (value <= 0xFFFFFFFF) {
                WriteVUInt64(4, value);
            } else if (value <= 0xFFFFFFFFFF) {
                WriteVUInt64(5, value);
            } else if (value <= 0xFFFFFFFFFFFF) {
                WriteVUInt64(6, value);
            } else if (value <= 0xFFFFFFFFFFFFFF) {
                WriteVUInt64(7, value);
            } else {
                WriteVUInt64(8, value);
            }
        }

        public void WriteVInt64(long value) {
            // 获取符号
            bool isNegative = value < 0 ? true : false;
            // 负数转为正数
            ulong bits = (ulong)(isNegative ? ~value : value);
            if (bits <= 0x7F) {
                WriteVUInt64(1, isNegative ? bits | 0x80 : bits);
            } else if (bits <= 0x7FFF) {
                WriteVUInt64(2, isNegative ? bits | 0x8000 : bits);
            } else if (bits <= 0x7FFFFF) {
                WriteVUInt64(3, isNegative ? bits | 0x800000 : bits);
            } else if (bits <= 0x7FFFFFFF) {
                WriteVUInt64(4, isNegative ? bits | 0x80000000 : bits);
            } else if (bits <= 0x7FFFFFFFFF) {
                WriteVUInt64(5, isNegative ? bits | 0x8000000000 : bits);
            } else if (bits <= 0x7FFFFFFFFFFF) {
                WriteVUInt64(6, isNegative ? bits | 0x800000000000 : bits);
            } else if (bits <= 0x7FFFFFFFFFFFFF) {
                WriteVUInt64(7, isNegative ? bits | 0x80000000000000 : bits);
            } else {
                WriteVUInt64(8, isNegative ? bits | 0x8000000000000000 : bits);
            }
        }
        #endregion

        #region API
        /// <summary> 填充字节 </summary>
        public void Fill(byte value, int byteCount) {
            EnsureCapacity(byteCount);
            for (int i = 0; i < byteCount; i++) {
                buffer[byteIndex++] = value;
            }
        }

        /// <summary> 把已写入的数据转换为字节数组 | Convert written data to byte array </summary>
        public byte[] ToBytes() {
            byte[] bytes = new byte[byteIndex];
            System.Buffer.BlockCopy(buffer, 0, bytes, 0, byteIndex);
            return bytes;
        }

        /// <summary> 字节数组容量 | Byte array capacity </summary>
        public int Capacity {
            get { return buffer.Length; }
            set {
                // 检查容量大小
                value = value <= 0 ? DefaultCapacity : value;
                value = value > buffer.Length ? value : buffer.Length;
                // 判断是否需要扩容
                if (value > buffer.Length) {
                    // 双倍扩容 留出剩余空间
                    value = value * 2;
                    if (value > MaxCapacity) {
                        // 超出最大容量 报错
                        throw new Exception($"LBNumberWriter.Buffer overflow! Expected Capacity:{value} > MaxCapacity:{MaxCapacity}");
                    } else {
                        // 扩容
                        byte[] newBuffer = new byte[value];
                        System.Buffer.BlockCopy(buffer, 0, newBuffer, 0, buffer.Length);
                        buffer = newBuffer;
                    }
                }
            }
        }

        /// <summary> 缓冲区 </summary>
        public byte[] Buffer {
            get { return buffer; }
        }

        /// <summary> 已写入数据的字节大小 | The byte size of the written data </summary>
        public int Length {
            get { return byteIndex; }
        }

        /// <summary> 当前写入的字节位置 | The byte location of the current write </summary>
        public int Position {
            get { return byteIndex; }
            set {
                value = value < 0 ? 0 : value;
                byteIndex = value;
                bitByteIndex = -1;
                bitIndex = 8;
            }
        }

        /// <summary> 擦除已写入的数据 以便重新使用(容量不变) | Erase written data for reuse </summary>
        public void Erase() {
            if (byteIndex == 0) return;
            Array.Clear(buffer, 0, byteIndex);
            Position = 0;
        }

        /// <summary> 释放并重置所有数据 | Release and reset all datas </summary>
        public void Dispose() {
            Position = 0;
            buffer = Array.Empty<byte>();
        }
        #endregion

        #region 工具 | Tools
        /// <summary> 确保有足够的空间 </summary>
        protected void EnsureCapacity(int byteCount) {
            int newCount = byteIndex + byteCount;
            if (newCount > buffer.Length) Capacity = newCount;
        }
        #endregion

    }

}